package com.imrookie.wrap;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 方法包装类
 * @author wangjiyu@imdada.cn
 * @create 2018/12/13
 */
public class MethodWrap {
    private String methodName;//方法名
    private Method method;//方法引用
    private ParameterWrap[] parameterWraps;//入参
    private ClassWrap rtn;//返回结果
    private GenericWrap rtnGenericWrap;//返回结果泛型信息
    private List<GenericWrap> generics;//涉及到的泛型,例如 T, E 等,返回方法声明时使用
    private int modifiers;//访问修饰符,数字类型,可以通过Modifier.toString(i)方法转为字符串

    public MethodWrap() {
    }

    public MethodWrap(Method method) {
        this.method = method;
        this.modifiers = method.getModifiers();
        this.methodName = method.getName();
        Parameter[] parameters = method.getParameters();
        if (parameters != null && parameters.length > 0) {
            this.parameterWraps = new ParameterWrap[parameters.length];
            for (int i=0;i<parameters.length;i++) {
                this.parameterWraps[i] = new ParameterWrap(parameters[i]);
            }
        }
        this.rtn = ClassWrap.getInstance(method.getReturnType());
        this.rtnGenericWrap = new GenericWrap(method.getGenericReturnType());
        TypeVariable<Method>[] typeVariables = method.getTypeParameters();//方法涉及到的泛型
        if (typeVariables != null && typeVariables.length > 0) {
            this.generics = new ArrayList<GenericWrap>();
            for (Type type : method.getTypeParameters()){
                this.generics.add(new GenericWrap(type));
            }
        }
    }

    @Override
    public String toString() {
        return "MethodWrap{" +
                "methodName='" + methodName + '\'' +
                ", parameterWraps=" + Arrays.toString(parameterWraps) +
                ", rtn=" + rtn.getClassName() +
                '}';
    }

    public String toStatementNoModifiers() {
        StringBuilder sb = new StringBuilder("");
        if (this.generics != null && this.generics.size() > 0) {//泛型声明
            sb.append("<");
            for (int i=0;i<this.generics.size();i++) {
                if (i > 0) {
                    sb.append(", ");
                }
                sb.append(this.generics.get(i).toStatement());
            }
            sb.append("> ");
        }
        return sb.append(rtnGenericWrap.isGenericFlag() ? rtnGenericWrap.toStatement() : rtn.getClassName()).append(" ").append(methodName).append("(").append(parametersToStatement()).append(")").append(";").toString();
    }

    public String toStatement() {
        StringBuilder sb = new StringBuilder("");
        sb.append(Modifier.toString(this.modifiers));
        if (sb.length() > 0) {
            sb.append(" ");
        }
        if (this.generics != null && this.generics.size() > 0) {//泛型声明
            sb.append("<");
            for (int i=0;i<this.generics.size();i++) {
                if (i > 0) {
                    sb.append(", ");
                }
                sb.append(this.generics.get(i).toStatement());
            }
            sb.append("> ");
        }
        return sb.append(rtnGenericWrap.isGenericFlag() ? rtnGenericWrap.toStatement() : rtn.getClassName()).append(" ").append(methodName).append("(").append(parametersToStatement()).append(")").append(";").toString();
    }

    public String parametersToStatement() {
        StringBuilder sb = new StringBuilder("");
        if (parameterWraps != null && parameterWraps.length > 0) {
            for (int i=0;i<parameterWraps.length;i++) {
                ParameterWrap parameterWrap = parameterWraps[i];
                //sb.append(", ").append(parameterWrap.getClassWrap().getClassName()).append(" ").append(parameterWrap.getClassWrap().getClassName().substring(0,1).toLowerCase() + parameterWrap.getClassWrap().getClassName().substring(1));
                sb.append(", ").append(parameterWrap.getGenericWrap().isGenericFlag() ? parameterWrap.getGenericWrap().toStatement() : parameterWrap.getClassWrap().getClassName()).append(" ").append(parameterWrap.getParameterName2());
                /*if (parameterWrap.getClassWrap().getClazz().isPrimitive()) {
                    sb.append(i);
                }*/
            }
            return sb.toString().substring(2);
        }
        return "";
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public ParameterWrap[] getParameterWraps() {
        return parameterWraps;
    }

    public void setParameterWraps(ParameterWrap[] parameterWraps) {
        this.parameterWraps = parameterWraps;
    }

    public ClassWrap getRtn() {
        return rtn;
    }

    public void setRtn(ClassWrap rtn) {
        this.rtn = rtn;
    }

    public GenericWrap getRtnGenericWrap() {
        return rtnGenericWrap;
    }

    public void setRtnGenericWrap(GenericWrap rtnGenericWrap) {
        this.rtnGenericWrap = rtnGenericWrap;
    }
}
